package controller;

import handlers.InventoryHandler;
import handlers.UnequipItemHandler;
import inventory.EquipLocation;
import inventory.EquippedInventory;
import inventory.Inventory;
import item.TakeableItem;

import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.ArrayList;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import model.Observer;
import model.Subject;
import pausing.Pauser;
import view.drawing.ImageLibrary;
import view.overlay.InventoryOverlay;
import entity.Entity;

public class InventoryController extends Controller implements Observer, InventoryOverlay.InventoryActionListener {
	
	private InventoryOverlay mInventoryOverlay;
	private Entity mEntity;
	
	private Inventory mEntityInventory;
	private EquippedInventory mEquippedInventory;
	
	private int mLowIndex;
	private int mHighIndex;
	
	private int mNumToDisplay;
	
	private GameControl mToggleControl;
	
	private InventoryHandler mInventoryHandler;
	private UnequipItemHandler mUnequipHandler;
	
	public InventoryController(Entity e, InventoryOverlay iOverlay) {
		mEntity = e;
		mInventoryOverlay = iOverlay;
		
		// Register to the Inventory
		mEntityInventory = e.getInventory();
		mEntityInventory.register(this);
		
		// Register to the EquippedInventory
		mEquippedInventory = e.getEquippedInventory();
		mEquippedInventory.register(this);
		
		mInventoryHandler = new InventoryHandler(e);
		mUnequipHandler = new UnequipItemHandler(e);
		

		
		mInventoryOverlay.setToggleButtonListener(new SimpleMouseListener() {

			@Override
			public void mouseClicked(MouseEvent e) {
				toggleInventory();
				
			}
		
		});
	}

	@Override
	public List<GameControl> getKeyControls() {
		mToggleControl = new TimedGameControl(KeyEvent.VK_I, "TOGGLE_INVENTORY", "Show/Hide Inventory", 500) {

			@Override
			protected void execute() {
				toggleInventory();
			}
			
		};
		mToggleControl.setEnabled(false);
		
		
		List<GameControl> ctrls = new ArrayList<GameControl>();
		
		ctrls.add(mToggleControl);
	
		
		return (ctrls);
	}

	/**
	 * Toggles the visibility of the Inventory
	 */
	private void toggleInventory() {
		if (mInventoryOverlay.toggleInventory()) {
			// Inventory is visible, pause game
			Pauser.pause();
		}
		else {
			Pauser.resume();
		}
	}
	
	/**
	 * Updates the overlay to display the new items
	 */
	private void updateOverlay() {
		
		Map<TakeableItem, MouseListener> itemMap = new HashMap<TakeableItem, MouseListener>();
		
		int lowerBound = 0;
		int upperBound = Math.min(mEntityInventory.getSize(), 5);
		// obtain the list, for now the first 5
		for (int i = lowerBound; i < upperBound; i++) {
			final TakeableItem item = mEntityInventory.getItem(i);
			
			if (item == null) continue;
			
			// Create a listener for it
			itemMap.put(item, new SimpleMouseListener() {

				@Override
				public void mouseClicked(MouseEvent e) {
					
					
					// determine if we want to drop or activate
					if (e.getButton() == MouseEvent.BUTTON1) {
						// trigger this item
						activateItem(item);
					}
					else if (e.getButton() == MouseEvent.BUTTON3){ 
						discardItem(item);
					}

					
				}
				
			});
			
		}
		
		// Assign the items to the overlay
		mInventoryOverlay.setInventoryItems(itemMap);
		
		Map<EquipLocation, MouseListener> listeners = new HashMap<EquipLocation, MouseListener>();
		
		
		
		// Update the map
		EnumMap<EquipLocation, TakeableItem> equippedItems = new EnumMap<EquipLocation, TakeableItem>(EquipLocation.class);
		
		for (final EquipLocation loc : EquipLocation.values()) {
			final TakeableItem item = mEquippedInventory.getItemAt(loc);
			
			if (item != null) {
				equippedItems.put(loc, item);
			}
			
			listeners.put(loc, new SimpleMouseListener() {

				@Override
				public void mouseClicked(MouseEvent e) {
					unequip(loc, item);
				}
				
			});
			
		}
		
		mInventoryOverlay.setEquippedItems(equippedItems, listeners);
	}
	
	private void discardItem(TakeableItem item) {
		mInventoryHandler.dropItem(item);
	}
	
	private void unequip(EquipLocation loc, TakeableItem item) {
		mUnequipHandler.unequip(loc);
	}
	
	
	private void activateItem(TakeableItem item) {
		mInventoryHandler.useItem(item);
		System.out.format("InventoryController::activateItem() > Item '%s' activated!\n", item.getName());
	}
	
	@Override
	public void update(Subject sourceSubject) {
		if ((sourceSubject.equals(mEntityInventory)) ||  (sourceSubject.equals(mEquippedInventory))) {
			// update the overlay
			updateOverlay();
		}
	}

	@Override
	public void nextPage() {
		if (mHighIndex < mEntityInventory.getSize()) {
			// we can go to another page
			mLowIndex += mNumToDisplay;
			mHighIndex += mNumToDisplay;
			
		}
		
	}
	
	public void activateInventory() {
		mToggleControl.setEnabled(true);
		mInventoryOverlay.setVisible(true);
	}
	
	public void deactivateInventory() {
		mToggleControl.setEnabled(false);
		mInventoryOverlay.hideInventory();
		mInventoryOverlay.setVisible(false);
	}
	

	@Override
	public void prevPage() {
		if (mLowIndex > 0) {
			
			mLowIndex = 0;
		}
		
	}
	
	@Override
	public void reset() {
		mInventoryOverlay.hideInventory();
	}
	
	
	

}
